#pragma once

#include "sock.hpp"
#include <sys/poll.h>
#include <poll.h>
#include <string>

#define BACK_LOG 5
#define NUM 5
#define DFL_FD -1

namespace  ns_poll
{
  
  class PollServer
  {
  public:
    PollServer(unsigned short port)
      :_port(port)
    {}
    void InitServer()
    {
      // 创建套接字
      _lsock = ns_sock::Sock::CreateSocket();
      // 绑定
      ns_sock::Sock::Bind(_lsock, _port);
      // 监听
      ns_sock::Sock::Listen(_lsock, BACK_LOG);
    }
    void Run()
    {
      struct pollfd rfds[NUM];
      // 将监听套接字添加到标记数组中
      rfds[0].fd = _lsock;
      rfds[0].events |= POLLIN;
      rfds[0].revents = 0;// 内核返回
      
      for (int i = 1; i < NUM; ++i)
      {
        rfds[i].fd = DFL_FD;
        rfds[i].events = 0;
        rfds[i].revents = 0;
      }

      while (1)
      {
        struct timeval timeout = {5, 0};
        int ret = poll(rfds, 64, -1);
        switch(ret)
        {
          case 0:
            std::cout << "timeout:" << timeout.tv_sec << std::endl;
            break;
          case -1:
            std::cerr << "poll error, errno is " << errno << std::endl;
            break;
          default:
            //std::cout << "to do something, timeout is " << timeout.tv_sec << std::endl;
            //std::cout << "changed fd num is " << ret << std::endl;
            HandEvent(rfds, NUM);
            //std::cout << "you can run here" << std::endl;
            break;
        }
      }
    }
    ~PollServer()
    {
      close(_lsock);
    }
  private:
    void HandEvent(struct pollfd rfds[], int size)
    {
      for (int i = 0; i < size; ++i)
      {
        if (rfds[i].fd == DFL_FD){
          continue;
        }
        if (rfds[i].revents&POLLIN){
          if (rfds[i].fd == _lsock){
            // 连接就绪
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sock = accept(_lsock, (struct sockaddr*)&peer, &len);
            
            std::string peerIp = inet_ntoa(peer.sin_addr);
            unsigned short peerPort = ntohs(peer.sin_port);
            
            std::cout << "get a new link:[" << peerIp << ":" << peerPort << "]" << std::endl; 
            // 把套接字添加到fd_array中，让poll等待读就绪
            AddFdToArray(rfds, NUM, sock);
          }
          else{
            // 读就绪
            char buf[1024];
            ssize_t sz = recv(rfds[i].fd, buf, sizeof(buf)-1, 0);
            if (sz > 0){
              buf[sz] = 0;
              std::cout << "echo# " << buf << std::endl;
            }
            else if (sz == 0){
              // 对端关闭
              std::cout << "client close" << std::endl;
              close(rfds[i].fd);
              rfds[i].fd = DFL_FD;
              rfds[i].events = 0;
              rfds[i].revents = 0;
            }
            else{
              std::cerr << "recv error" << std::endl;
            }
          }// end if
        }// end if
      }  
    }
    void Print(int fd_array[], int size, fd_set* rfds)
    {
      for (int i = 0; i < size; ++i)
      {
        if (FD_ISSET(fd_array[i], rfds)){
          std::cout << "1";
        }
        else{
          std::cout << "0";
        }
      }
      std::cout << std::endl;
    }
    bool AddFdToArray(struct pollfd* rfds, int size, int sock)
    {
      for (int i = 0; i < size; ++i)
      {
        if (rfds[i].fd == DFL_FD){
          rfds[i].fd = sock;
          rfds[i].events |= POLLIN;
          rfds[i].revents = 0;
          return true;
        }
      }
      return false;
    }
    void InitArray(int fd_array[], int size, int flag)
    {
      for (int i = 0; i < size; ++i)
      {
        fd_array[i] = flag;
      }
    }
  private:
    unsigned short _port;
    int _lsock;
  };
}
